//
//  Fresnel.cpp
//  RayTracer
//
//  Created by 俞云康 on 3/25/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#include "Fresnel.hpp"

// (i)ncident media
// (t)ransmitted media
// cos: cos(\theta)
// eta: index of refraction
float fresnel_dielectric(float cos_i, float cos_t, float eta_i, float eta_t) {
    float r_parallel      = (eta_t*cos_i - eta_i*cos_t) / (eta_t*cos_i + eta_i*cos_t);
    float r_perpendicular = (eta_i*cos_i - eta_t*cos_t) / (eta_i*cos_i + eta_t*cos_t);
    return (r_parallel*r_parallel + r_perpendicular*r_perpendicular) / 2.0f;
}

Color fresnel_conductor(float cos_i, Color eta_i, Color k) {
    Color tmp = (eta_i*eta_i + k*k) * cos_i * cos_i;
    Color r_parallel2 = (tmp - (2.0f*eta_i*cos_i) + 1) / (tmp + (2.0f*eta_i*cos_i) + 1);
    Color tmp_f = eta_i*eta_i + k*k;
    Color r_perpendicular2 =    (tmp_f-(2.0f*eta_i*cos_i)+cos_i*cos_i) / (tmp_f+(2.0f*eta_i*cos_i)+cos_i*cos_i);
    return (r_parallel2 + r_perpendicular2) / 2.0f;
}


Color FresnelDialectric::Evaluate(float cos_i) const {
    cos_i = clamp(cos_i, -1.f, 1.f);
    bool entering = cos_i > 0;
    float ei = eta_i, et = eta_t;
    if (!entering) { std::swap(ei, et); }
    
    // compute sin_t using Snell's law
    float sin_t = ei/et * sqrtf(std::max(0.f, 1.f - cos_i*cos_i));
    if (sin_t >= 1.f) {  // handle total internal reflection
        //info("total internal reflection\n");
        return Color(1.f, 1.f, 1.f);
    }
    else {
        float cos_t = sqrtf(std::max(0.f, 1.f - sin_t*sin_t));
        float c = fresnel_dielectric(fabsf(cos_i), cos_t, ei, et);
        return Color(c, c, c);
    }
}

Color FresnelConductor::Evaluate(float cos_i) const {
    return fresnel_conductor(fabsf(cos_i), eta, k);
}